#ifndef SPRITEBATCH_H
#define SPRITEBATCH_H

#include "Rect.h"
#include "Texture2D.h"
#include "Vector2.h"
#include "Colors.h"
#include "Vertices.h"
#include "Renderer.h"

namespace Cvekas {

/// Represents single sprite. For internal use only.
struct Sprite
{
	// Default constructor
	Sprite();

	// Copy constructor
	Sprite(const Sprite& s);

	// Sort operator
	bool operator<(const Sprite& s);

	// Equality operator
	bool operator==(const Sprite& s);

	RectF source, dest;
	Color color;
	Texture2DPtr texture;
	int layer;
	float rotation;
};

/// Interval of sprites with same texture and layer. For internal use only.
struct SpriteSpan
{
	uint first, count;
};

/// Class for batch rendering of sprites
class SpriteBatch : public Renderable, public boost::noncopyable
{
public:
	/// Constructor
	/// \param renderer Renderer to which this sprite will send batches
	/// \param virtual_width Virtual resolution width
	/// \param virtual_height Virtual resolution height
	/// \param base_priority Base priority value of generated batches.
	/// Individual priority for each batch is calculated like this: base_priority + sprite_layer
	SpriteBatch(RendererPtr renderer, uint virtual_width, uint virtual_height, uint16 base_priority = 1000);
	
	/// Destructor
	virtual ~SpriteBatch();

	/// Prepares batches and registers for rendering. Must be called after all drawing in current frame is done.
	void present(uint technique = 0);

	/// Sets new effect. Default effect is provided, so it is not required to set it.
	/// Default effect is named %SpriteBatch and is loaded from file default_effect_file
	void setEffect(EffectPtr effect);
	
	/// Draws a textured rectangle
	/// \param texture Pointer to texture which will be used
	/// \param layer Layer of rectangle. Rectangles with with lower layer number are always
	///		drawn on top rectangles with higher layer.
	/// \param source Portion of texture which will be visible
	/// \param dest Location where texture will be placed
	/// \param color Tint color (White means no tinting)
	void draw(Texture2DPtr texture, uint layer, const RectF& source, const RectF& dest, 
		const Color& color = Color(255, 255, 255, 255), float rotation = 0.0f);
	
	/// Draws a textured rectangle
	/// \param texture Pointer to texture which will be used
	/// \param layer Layer of rectangle. Rectangles with with lower layer number are always
	///		drawn on top rectangles with higher layer.
	/// \param source Portion of texture which will be visible
	/// \param location Location where top left corner of texture will be placed
	/// \param color Tint color (White means no tinting)
	void draw(Texture2DPtr texture, uint layer, const RectF& source, const Vector2& location, 
		const Color& color = Color(255, 255, 255, 255));
		
	/// Draws a textured rectangle
	/// \param texture Pointer to texture which will be used
	/// \param layer Layer of rectangle. Rectangles with with lower layer number are always
	///		drawn on top rectangles with higher layer.
	/// \param location Location where top left corner of texture will be placed
	/// \param color Tint color (White means no tinting)
	void draw(Texture2DPtr texture, uint layer, const Vector2& location, 
		const Color& color = Color(255, 255, 255, 255));

	/// Sets new virtual resolution
	void setVirtualResolution(uint width, uint height) { virtual_width = width; virtual_height = height; };
	
	// Renderable implementation
	virtual void onPreRender(uint16 batch_id);
	virtual uint getBatches(Batch** batches);

private:
	void build_ib();
	void build_batches(uint technique);

	static const uint max_sprites = 4096;
	static const uint max_spans = 512;

	RendererPtr renderer;
	EffectPtr effect;
	ParamHandle texture_param;

	IndexBufferPtr index_buffer;
	VertexBufferPtr vertex_buffer;
	
	static int vertex_buffer_name_counter;

	boost::array<Sprite, max_sprites> sprites;
	boost::array<SpriteSpan, max_spans> spans;
	boost::array<Batch, max_spans> batches;

	uint sprite_count, span_count, virtual_width, virtual_height;
	uint16 base_priority;
	
	bool presented;
};

typedef boost::shared_ptr<SpriteBatch> SpriteBatchPtr;

}

#endif
